//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.catchman.controller.common;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.catchman.annotation.OperationLog;
import com.catchman.annotation.PermInfo;
import com.catchman.constant.PermType;
import com.catchman.entity.SysPerm;
import com.catchman.service.SysPermService;
import com.catchman.utils.RuntimeUtil;
import com.catchman.utils.SysPermUtil;
import com.catchman.utils.SysPermUtil.PermVo;
import com.catchman.vo.ResponseModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author catchman
 */
@Api(tags = {"系统接口文档、监控、数据库管理控制器"})
@PermInfo(pval = "sys:key:*", value = "控制系统API、sql监控、数据库管理等关键服务")
@Controller
@RequestMapping({"/sys"})
public class SysController {
    private static final Logger logger = LoggerFactory.getLogger(SysController.class);
    @Value("${sql.backup.path}")
    private String sqlBackUpPath;
    @Value("${sql.backup.command}")
    private String sqlBackUpCmd;
    @Value("${sql.restore.command}")
    private String sqlRestoreCmd;
    @Value("${sql.backup.fileName}")
    private String sqlBackUpFileName;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private SysPermService sysPermService;

    @OperationLog("访问swagger2接口文档")
    @ApiOperation("访问swagger2接口文档")
    @RequiresPermissions({"sys:key:swagger2"})
    @GetMapping({"/monitor/swagger"})
    public ModelAndView swagger2UI() {
        return new ModelAndView("redirect:/swagger-ui.html");
    }

    @OperationLog("请求druid sql监控")
    @ApiOperation("druid sql监控")
    @RequiresPermissions({"sys:key:druid"})
    @GetMapping({"/monitor/druid"})
    public ModelAndView druidUI() {
        return new ModelAndView("redirect:/druid/login.html");
    }

    @ResponseBody
    @OperationLog("数据库备份")
    @ApiOperation("数据库备份")
    @RequiresPermissions({"sys:key:db:backup"})
    @PostMapping({"/backup/db/all"})
    public ResponseModel dbBackup() {
        String oper = "backup all database";
        try {
            if (backUpDataBase()) {
                logger.info("operation: {}", oper + " successfully");
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("operation: {},cause:{}", oper + " failed", e.getLocalizedMessage());
            return ResponseModel.fail(oper).msg(e.getLocalizedMessage());
        }
        return ResponseModel.succ(oper);
    }

    /**
     * 备份数据库函数,便于其他地方调用（比如定时任务）
     *
     * @return true/false
     */
    public boolean backUpDataBase() throws IOException, InterruptedException {
        String sqlCmd;
        String fp = this.sqlBackUpPath + File.separator + (new Date()).getTime();
        File f = new File(fp);
        if (!f.exists()) {
            f.mkdirs();
        }
        sqlCmd = this.sqlBackUpCmd.replace(this.sqlBackUpPath, fp);
        if (!RuntimeUtil.excuteCmd(sqlCmd)) {
            throw new RuntimeException("Error executing the command");
        }
        return true;
    }

    @ResponseBody
    @OperationLog("数据库恢复")
    @ApiOperation("数据库恢复")
    @ApiImplicitParam(name = "数据库备份的时间戳", value = "1557290217892")
    @RequiresPermissions({"sys:key:db:restore"})
    @PostMapping({"/restore/db/all"})
    public ResponseModel dbRestore(@RequestParam long dbFileTime) {
        String oper = "restore all database";
        String sqlCmd = null;

        try {
            String fp = this.sqlBackUpPath + File.separator + dbFileTime + File.separator + this.sqlBackUpFileName;
            File f = new File(fp);
            if (!f.exists()) {
                throw new Throwable("还原sql" + f.getAbsolutePath() + "文件不存在！检查是否更改过数据库备份位置、以及备份文件名！");
            }

            sqlCmd = this.sqlRestoreCmd.replace(this.sqlBackUpPath + "/" + this.sqlBackUpFileName, fp);
            if (RuntimeUtil.excuteCmd(sqlCmd)) {
                logger.info("operation: {}, command: {}", oper + " successfully!", sqlCmd);
                return ResponseModel.succ(oper);
            }
        } catch (Throwable throwable) {
            logger.error("operation: {}, command: {},cause:{}", oper + " failed!", sqlCmd, throwable.getLocalizedMessage());
        }

        return ResponseModel.fail(oper);
    }

    @ResponseBody
    @OperationLog("同步系统API权限信息")
    @ApiOperation("同步系统API权限信息")
    @RequiresPermissions({"sys:key:perm:sync"})
    @PostMapping({"/perm/sync"})
    public ResponseModel permSync() {
        String basicPackage = ClassUtils.getPackageName(this.getClass());
        String controllerPackage = basicPackage.substring(0, basicPackage.indexOf("controller") + "controller".length());
        List<PermVo> permVoList = SysPermUtil.getAnnoPerm(this.applicationContext, controllerPackage);
        List<SysPerm> sysPermList = this.getSysPerms(permVoList, "*");
        List<SysPerm> apiList = new ArrayList();
        this.listAll(apiList, sysPermList);
        if (!apiList.isEmpty()) {
            this.sysPermService.remove(new QueryWrapper<SysPerm>().eq("ptype", PermType.API));
            this.sysPermService.saveOrUpdate(apiList);
        }
        logger.info("{}", "sync system perm");
        return ResponseModel.succ();
    }

    /**
     * 递归 提升children List<SysPerm>
     *
     * @param apiList
     * @param sysPermList
     */
    private void listAll(List<SysPerm> apiList, List<SysPerm> sysPermList) {
        for (SysPerm s : sysPermList) {
            apiList.add(s);
            if (s.getChildren() != null && !s.getChildren().isEmpty()) {
                this.listAll(apiList, s.getChildren());
            }
        }
    }

    /**
     * 映射SysPerm对象list 和 PermVo对象list
     *
     * @param permVoList
     * @param parent
     * @return
     */
    private List<SysPerm> getSysPerms(List<PermVo> permVoList, String parent) {
        return permVoList.stream().map((permVo) -> {
            SysPerm sysPerm = new SysPerm();
            sysPerm.setPname(permVo.getPname());
            sysPerm.setPval(permVo.getPval());
            sysPerm.setParent(parent);
            sysPerm.setLeaf(true);
            sysPerm.setCreated(LocalDateTime.now());
            if (permVo.getChildren() != null && !permVo.getChildren().isEmpty()) {
                List<SysPerm> list = this.getSysPerms(permVo.getChildren(), permVo.getPval());
                sysPerm.setChildren(list);
            }
            sysPerm.setPtype(PermType.API);
            return sysPerm;
        }).collect(Collectors.toList());
    }



}
